package cn.com.joycode.nimble.starter.examples;

import cn.com.joycode.nimble.core.utils.ObjectMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class esAdd extends BaseTest {

    @Autowired
    private NewsRepository newsRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Test
    public void addNews() {
        for (int i = 0; i < 1000; i++) {
            News news = new News();
            news.setId(Integer.toString(i));
            news.setAuthor("Max Woods ".concat(news.getId()));
            news.setName("Book ".concat(news.getId()));
            newsRepository.save(news);
        }
    }

    @Test
    public void query() {
        List<News> newsList = newsRepository.findByNameLike("bo");
        log.info("count:{}", newsList.size());
    }

    @Test
    public void search() {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("news").withTypes("news")
                .withQuery(QueryBuilders.queryStringQuery("Book"))
                .withPageable(PageRequest.of(0, 20))
                .build();
        List<News> list = elasticsearchTemplate.queryForList(searchQuery, News.class);
        log.info("count:{} ", list.size());
    }

    @Test
    public void match() {
        Pageable pageable = PageRequest.of(0, 10, new Sort(Sort.Direction.ASC, "author"));
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("news").withTypes("news")
                .withQuery(QueryBuilders.multiMatchQuery("Max Woods", "name", "author"))
                .withPageable(pageable)
                .build();
        List<News> list = elasticsearchTemplate.queryForList(searchQuery, News.class);
        log.info("count:{} ", list.size());
    }

    @Test
    public void light() {
        Pageable pageable = PageRequest.of(0, 10, new Sort(Sort.Direction.ASC, "author"));
        HighlightBuilder.Field field = new HighlightBuilder.Field("author").preTags("<em>").postTags("</em");
        TermsAggregationBuilder sortField = AggregationBuilders.terms("author").field("author");
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("news").withTypes("news")
                .addAggregation(sortField)
                .withQuery(QueryBuilders.multiMatchQuery("Max Woods", "name", "author"))
                .withPageable(pageable).withHighlightFields(field).build();
        List<News> list = elasticsearchTemplate.queryForList(searchQuery, News.class);
        log.info("count:{} ", list.size());
        list.forEach(
                news ->
                        log.info("author:{}", news.getAuthor())
        );
    }

    @Test
    public void high() {
        Pageable pageable = PageRequest.of(0, 10, new Sort(Sort.Direction.ASC, "author"));
        HighlightBuilder.Field field = new HighlightBuilder.Field("author").preTags("<em>").postTags("</em");
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery("Max Woods", "name", "author"))
                .withPageable(pageable).withHighlightFields(field).build();
        // 高亮字段
        AggregatedPage<News> page = elasticsearchTemplate.queryForPage(searchQuery, News.class, new SearchResultMapper() {

            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {

                List<T> chunk = new ArrayList<>();
                searchResponse.getHits().forEach(
                        searchHit ->
                        {
                            Map<String, Object> smap = searchHit.getSourceAsMap();
                            Map<String, HighlightField> hmap = searchHit.getHighlightFields();
                            String high = hmap.get("author").fragments()[0].toString();
                            smap.put("author", high);
                            News news = ObjectMapperUtil.convertValue(smap, News.class);
                            chunk.add((T) news);
                        }
                );
                AggregatedPage<T> result = new AggregatedPageImpl<T>(chunk, pageable, searchResponse.getHits().getTotalHits());
                return result;
            }

            @Override
            public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                log.info("hint");
                return null;
            }
        });

        page.getContent().forEach(
                news ->
                {
                    log.info("高亮匹配:{}", news);
                }
        );
        log.info("内容:{}",ObjectMapperUtil.toJsonString(page.getContent()));


    }

}
